using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace Spike.ContractBuilder.Host
{
    public class StubHostService
    {
        struct StubTestResult
        {
            public StubTestResult(Type typeOfHost, string method)
            {
                _typeOfHost = typeOfHost;
                _method = method;
            }
            internal Type _typeOfHost;
            internal string _method;
        }

        private static StubHostService _instance;
        public static StubHostService Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new StubHostService();
                }
                return _instance;
            }
        }

        Dictionary<StubTestResult, List<TestResult>> _testResults = new Dictionary<StubTestResult, List<TestResult>>();

        public void AddResult(Type typeOfHost, string method, TestResult result)
        {            
            
            StubTestResult key = new StubTestResult(typeOfHost, method);
            List<TestResult> results = null;

            if (!_testResults.TryGetValue(key, out results))
            {
                results = new List<TestResult>();
                _testResults.Add(key, results);
            }

            results.Add(result);            
        }

        public void ClearTestResults(Type typeOfHost, string method)
        {
            _testResults.Remove(new StubTestResult(typeOfHost, method));
        }


        /// <summary>
        /// The DynamicServiceHost will call this method when determining a response.  if a response
        /// has been loaded against the typeofhost and matching the parameters, then the response will be
        /// returned.  Otherwise a random response will be generated.
        /// </summary>
        /// <param name="typeOfHost"></param>
        /// <param name="parameters"></param>
        /// <param name="typeOfResponse"></param>
        /// <returns></returns>
        public object GetObject(Type typeOfHost, string method, object[] parameters, Type typeOfResponse)
        {
            object response = null;
            
            bool wasStubbed = GetStubResponse(typeOfHost, method, parameters, out response);

            if (wasStubbed == false)
                return ContractHelper.GetRandomObject(typeOfResponse);
            else
                return response;
        }

        private bool GetStubResponse(Type typeOfHost, string method, object[] parameters, out object response)
        {
            response = null;
            bool wasStubbed = false;

            StubTestResult key = new StubTestResult(typeOfHost, method);
            List<TestResult> results = null;

            if (_testResults.TryGetValue(key, out results))
            {
                // loop through each test result until one is found
                foreach (TestResult result in results)
                {                    
                    wasStubbed = result.Evaluate(parameters, out response);
                    if (wasStubbed)
                        break;
                }
            }

            return wasStubbed;
        }
        
    }
}
